﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
using System.Diagnostics;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Diagnostics.CodeAnalysis;
using System.Web.Script.Serialization;
using System.Runtime.Serialization.Json;

namespace Lilium.Web.Mvc.AjaxControlToolkit
{
	/// <summary>
	/// Extender that provides suggestions to fill input in a textbox.
	/// </summary>
	[RequiredResource(typeof(CommonToolkitScripts), LoadOrder = 0)]
	[RequiredResource(typeof(PopupExtender), LoadOrder = 1)]
	[RequiredResource(typeof(TimerScript), LoadOrder = 2)]
	[RequiredResource(typeof(AnimationExtender), LoadOrder = 3)]
	[JavaScriptReference(Constants.ToolkitLibraryName, "AutoComplete.AutoCompleteBehavior.js", LoadOrder = 4)]
	public class AutoCompleteExtender: AnimationExtenderControlBase
	{
		public AutoCompleteExtender(string elementID)
			: base("AjaxControlToolkit.AutoCompleteBehavior", elementID)
		{
		}

		#region public int MinimumPrefixLength

		private int m_MinimumPrefixLength = 3;

		/// <summary>
		/// Minimum length of text before the webservice provides suggestions.
		/// </summary>
		[DefaultValue(3)]
		[ExtenderControlProperty]
		[ClientPropertyName("minimumPrefixLength")]
		public int MinimumPrefixLength { [DebuggerNonUserCodeAttribute] get { return m_MinimumPrefixLength; } [DebuggerNonUserCodeAttribute] set { m_MinimumPrefixLength = value; } }

		#endregion

		#region public int CompletionInterval

		private int m_CompletionInterval = 1000;

		/// <summary>
		/// Time in milliseconds when the timer will kick in to get suggestions using the web service. 
		/// </summary>
		[DefaultValue(1000)]
		[ExtenderControlProperty]
		[ClientPropertyName("completionInterval")]
		public int CompletionInterval { [DebuggerNonUserCodeAttribute] get { return m_CompletionInterval; } [DebuggerNonUserCodeAttribute] set { m_CompletionInterval = value; } }

		#endregion

		#region public int CompletionSetCount

		private int m_CompletionSetCount = 10;

		/// <summary>
		/// Number of suggestions to be provided.
		/// </summary>
		[DefaultValue(10)]
		[ExtenderControlProperty]
		[ClientPropertyName("completionSetCount")]
		public int CompletionSetCount { [DebuggerNonUserCodeAttribute] get { return m_CompletionSetCount; } [DebuggerNonUserCodeAttribute] set { m_CompletionSetCount = value; } }

		#endregion

		#region public string CompletionListElementID

		private string m_CompletionListElementID = "";

		/// <summary>
		/// ID of element that will serve as the completion list.
		/// </summary>
		[DefaultValue("")]
		[ExtenderControlProperty]
		[ClientPropertyName("completionListElementID")]
		//[IDReferenceProperty(typeof(WebControl))]
		[Obsolete("Instead of passing in CompletionListElementID, use the default flyout and style that using the CssClass properties.")]
		[SuppressMessage("Microsoft.Naming", "CA1706:ShortAcronymsShouldBeUppercase", MessageId = "Member")]
		public string CompletionListElementID { [DebuggerNonUserCodeAttribute] get { return m_CompletionListElementID; } [DebuggerNonUserCodeAttribute] set { m_CompletionListElementID = value; } }

		#endregion

		#region public string ServiceMethod

		private string m_ServiceMethod;

		/// <summary>
		/// The web service method to be called.
		/// </summary>
		[DefaultValue("")]
		[RequiredProperty]
		[ExtenderControlProperty]
		[ClientPropertyName("serviceMethod")]
		public string ServiceMethod { [DebuggerNonUserCodeAttribute] get { return m_ServiceMethod ?? string.Empty; } [DebuggerNonUserCodeAttribute] set { m_ServiceMethod = value; } }

		#endregion

		#region public string ServicePath

		private string m_ServicePath;

		/// <summary>
		/// The path to the web service that the extender will pull the 
		/// word\sentence completions from. If this is not provided, the 
		/// service method should be a page method. 
		/// </summary>
		[UrlProperty]
		[ExtenderControlProperty]
		[TypeConverter(typeof(ServicePathConverter))]
		[ClientPropertyName("servicePath")]
		public string ServicePath { [DebuggerNonUserCodeAttribute] get { return m_ServicePath; } [DebuggerNonUserCodeAttribute] set { m_ServicePath = value; } }

		#endregion

		#region public string ContextKey

		private string m_ContextKey;

		/// <summary>
		/// User/page specific context provided to an optional overload of the
		/// web method described by ServiceMethod/ServicePath.  If the context
		/// key is used, it should have the same signature with an additional
		/// parameter named contextKey of type string.
		/// </summary>
		[ExtenderControlProperty]
		[ClientPropertyName("contextKey")]
		[DefaultValue(null)]
		public string ContextKey
		{
			[DebuggerNonUserCodeAttribute]
			get { return m_ContextKey; }
			[DebuggerNonUserCodeAttribute]
			set
			{
				m_ContextKey = value;
				UseContextKey = true;
			}
		}

		#endregion

		#region public bool UseContextKey

		private bool m_UseContextKey;

		/// <summary>
		/// Whether or not the ContextKey property should be used.  This will be
		/// automatically enabled if the ContextKey property is ever set
		/// (on either the client or the server).  If the context key is used,
		/// it should have the same signature with an additional parameter
		/// named contextKey of type string.
		/// </summary>
		public bool UseContextKey { [DebuggerNonUserCodeAttribute] get { return m_UseContextKey; } [DebuggerNonUserCodeAttribute] set { m_UseContextKey = value; } }

		#endregion

		#region public string CompletionListCssClass

		private string m_CompletionListCssClass;

		/// <summary>
		/// Css Class that will be used to style the completion list flyout.
		/// </summary>
		[DefaultValue("")]
		[ExtenderControlProperty]
		[ClientPropertyName("completionListCssClass")]
		public string CompletionListCssClass { [DebuggerNonUserCodeAttribute] get { return m_CompletionListCssClass ?? string.Empty; } [DebuggerNonUserCodeAttribute] set { m_CompletionListCssClass = value; } }

		#endregion

		#region public string CompletionListItemCssClass

		private string m_CompletionListItemCssClass;

		/// <summary>
		/// Css Class that will be used to style an item in the autocomplete list.
		/// </summary>
		[DefaultValue("")]
		[ExtenderControlProperty]
		[ClientPropertyName("completionListItemCssClass")]
		public string CompletionListItemCssClass { [DebuggerNonUserCodeAttribute] get { return m_CompletionListItemCssClass ?? string.Empty; } [DebuggerNonUserCodeAttribute] set { m_CompletionListItemCssClass = value; } }

		#endregion

		#region public string CompletionListHighlightedItemCssClass

		private string m_CompletionListHighlightedItemCssClass;

		/// <summary>
		/// Css Class that will be used to style a highlighted item in the autocomplete list.
		/// </summary>
		[DefaultValue("")]
		[ExtenderControlProperty]
		[ClientPropertyName("highlightedItemCssClass")]
		public string CompletionListHighlightedItemCssClass { [DebuggerNonUserCodeAttribute] get { return m_CompletionListHighlightedItemCssClass ?? string.Empty; } [DebuggerNonUserCodeAttribute] set { m_CompletionListHighlightedItemCssClass = value; } }

		#endregion

		#region public bool EnableCaching

		private bool m_EnableCaching = true;

		/// <summary>
		/// Flag to denote whether client side caching is enabled.
		/// </summary>
		[DefaultValue(true)]
		[ExtenderControlProperty]
		[ClientPropertyName("enableCaching")]
		public bool EnableCaching { [DebuggerNonUserCodeAttribute] get { return m_EnableCaching; } [DebuggerNonUserCodeAttribute] set { m_EnableCaching = value; } }

		#endregion

		#region public string DelimiterCharacters

		private string m_DelimiterCharacters;

		/// <summary>
		/// Gets or sets the character(s) used to separate words for autocomplete.
		/// </summary>
		[ExtenderControlProperty]
		[ClientPropertyName("delimiterCharacters")]
		public string DelimiterCharacters { [DebuggerNonUserCodeAttribute] get { return m_DelimiterCharacters; } [DebuggerNonUserCodeAttribute] set { m_DelimiterCharacters = value; } }

		#endregion

		#region public bool FirstRowSelected

		private bool m_FirstRowSelected;

		/// <summary>
		/// Determines if the First Row of the Search Results be selected by default
		/// </summary>
		[DefaultValue(false)]
		[ExtenderControlProperty]
		[ClientPropertyName("firstRowSelected")]
		public bool FirstRowSelected { [DebuggerNonUserCodeAttribute] get { return m_FirstRowSelected; } [DebuggerNonUserCodeAttribute] set { m_FirstRowSelected = value; } }

		#endregion

		#region public bool ShowOnlyCurrentWordInCompletionListItem

		private bool m_ShowOnlyCurrentWordInCompletionListItem;

		/// <summary>
		/// If Delimiter characters are specified and ShowOnlyCurrentWordInCompletionListItem is 
		/// set to true, then the completion list displays suggestions just for the current word, 
		/// otherwise, it displays the whole string that will show up in the TextBox if that
		/// item is selected, which is the current default.
		/// </summary>
		[SuppressMessage("Microsoft.Naming", "CA1702:CompoundWordsShouldBeCasedCorrectly", MessageId = "InCompletion")]
		[ExtenderControlProperty]
		[ClientPropertyName("showOnlyCurrentWordInCompletionListItem")]
		[DefaultValue(false)]
		public bool ShowOnlyCurrentWordInCompletionListItem { [DebuggerNonUserCodeAttribute] get { return m_ShowOnlyCurrentWordInCompletionListItem; } [DebuggerNonUserCodeAttribute] set { m_ShowOnlyCurrentWordInCompletionListItem = value; } }

		#endregion

		#region public Animation OnShow

		private Animation m_OnShow;

		/// <summary>
		/// OnShow animation
		/// </summary>
		[ExtenderControlProperty]
		[ClientPropertyName("onShow")]
		[Browsable(false)]
		[DefaultValue(null)]
		[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
		public Animation OnShow { [DebuggerNonUserCodeAttribute] get { return m_OnShow; } [DebuggerNonUserCodeAttribute] set { m_OnShow = value; } }

		#endregion

		#region public Animation OnHide

		private Animation m_OnHide;

		/// <summary>
		/// OnHide animation
		/// </summary>
		[ExtenderControlProperty]
		[ClientPropertyName("onHide")]
		[Browsable(false)]
		[DefaultValue(null)]
		[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
		public Animation OnHide { [DebuggerNonUserCodeAttribute] get { return m_OnHide; } [DebuggerNonUserCodeAttribute] set { m_OnHide = value; } }

		#endregion

		#region public string OnClientPopulating

		private string m_OnClientPopulating;

		/// <summary>
		/// Handler to attach to the client-side populating event
		/// </summary>
		[DefaultValue("")]
		[ExtenderControlEvent]
		[ClientPropertyName("populating")]
		public string OnClientPopulating { [DebuggerNonUserCodeAttribute] get { return m_OnClientPopulating ?? string.Empty; } [DebuggerNonUserCodeAttribute] set { m_OnClientPopulating = value; } }

		#endregion

		#region public string OnClientPopulated

		private string m_OnClientPopulated;

		/// <summary>
		/// Handler to attach to the client-side populated event
		/// </summary>
		[DefaultValue("")]
		[ExtenderControlEvent]
		[ClientPropertyName("populated")]
		public string OnClientPopulated { [DebuggerNonUserCodeAttribute] get { return m_OnClientPopulated ?? string.Empty; } [DebuggerNonUserCodeAttribute] set { m_OnClientPopulated = value; } }

		#endregion

		#region public string OnClientShowing

		private string m_OnClientShowing;

		/// <summary>
		/// Handler to attach to the client-side showing event
		/// </summary>
		[DefaultValue("")]
		[ExtenderControlEvent]
		[ClientPropertyName("showing")]
		public string OnClientShowing { [DebuggerNonUserCodeAttribute] get { return m_OnClientShowing ?? string.Empty; } [DebuggerNonUserCodeAttribute] set { m_OnClientShowing = value; } }

		#endregion

		#region public string OnClientShown

		private string m_OnClientShown;

		/// <summary>
		/// Handler to attach to the client-side hiding event
		/// </summary>
		[DefaultValue("")]
		[ExtenderControlEvent]
		[ClientPropertyName("hiding")]
		public string OnClientShown { [DebuggerNonUserCodeAttribute] get { return m_OnClientShown ?? string.Empty; } [DebuggerNonUserCodeAttribute] set { m_OnClientShown = value; } }

		#endregion

		#region public string OnClientHidden

		private string m_OnClientHidden;

		/// <summary>
		/// Handler to attach to the client-side hidden event
		/// </summary>
		[DefaultValue("")]
		[ExtenderControlEvent]
		[ClientPropertyName("hidden")]
		public string OnClientHidden { [DebuggerNonUserCodeAttribute] get { return m_OnClientHidden ?? string.Empty; } [DebuggerNonUserCodeAttribute] set { m_OnClientHidden = value; } }

		#endregion

		#region public string OnClientItemSelected

		private string m_OnClientItemSelected;

		/// <summary>
		/// Handler to attach to the client-side itemSelected event
		/// </summary>
		[DefaultValue("")]
		[ExtenderControlEvent]
		[ClientPropertyName("itemSelected")]
		public string OnClientItemSelected { [DebuggerNonUserCodeAttribute] get { return m_OnClientItemSelected ?? string.Empty; } [DebuggerNonUserCodeAttribute] set { m_OnClientItemSelected = value; } }

		#endregion

		#region public string OnClientItemOver

		private string m_OnClientItemOver;

		/// <summary>
		/// Handler to attach to the client-side itemOver event
		/// </summary>
		[DefaultValue("")]
		[ExtenderControlEvent]
		[ClientPropertyName("itemOver")]
		public string OnClientItemOver { [DebuggerNonUserCodeAttribute] get { return m_OnClientItemOver ?? string.Empty; } [DebuggerNonUserCodeAttribute] set { m_OnClientItemOver = value; } }

		#endregion

		#region public string OnClientItemOut

		private string m_OnClientItemOut;

		/// <summary>
		/// Handler to attach to the client-side itemOut event
		/// </summary>
		[DefaultValue("")]
		[ExtenderControlEvent]
		[ClientPropertyName("itemOut")]
		public string OnClientItemOut { [DebuggerNonUserCodeAttribute] get { return m_OnClientItemOut ?? string.Empty; } [DebuggerNonUserCodeAttribute] set { m_OnClientItemOut = value; } }

		#endregion

		/// <summary>
		/// Create a serialized JSON object representing a text/value pair that can
		/// be returned by the webservice.
		/// </summary>
		/// <param name="text">Text</param>
		/// <param name="value">Value</param>
		/// <returns>serialized JSON object representing the text/value pair</returns>
		public static string CreateAutoCompleteItem(string text, string value)
		{
			return new JavaScriptSerializer().Serialize(new Pair(text, value));
		}

		public static object CreateCompletionList(IEnumerable<Pair> items)
		{
			if (items == null)
				throw new ArgumentNullException("items");

			var serializer = new JavaScriptSerializer();
			return new 
			{
				d = items.Select(a => serializer.Serialize(a)).ToArray(),
			};
		}

		public static object CreateCompletionList(IEnumerable<string> items)
		{
			if (items == null)
				throw new ArgumentNullException("items");
			return new
			{
				d = items.ToArray(),
			};
		}
	}
}